package cn.schoolwow.quickflow.executor;

import cn.schoolwow.quickflow.domain.FlowConfig;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.domain.FlowExecutorConfig;
import cn.schoolwow.quickflow.domain.FlowExecutorRootConfig;
import cn.schoolwow.quickflow.exception.BrokenCurrentCompositeBusinessException;
import cn.schoolwow.quickflow.exception.BrokenCurrentFlowException;
import cn.schoolwow.quickflow.exception.BrokenException;
import cn.schoolwow.quickflow.exception.QuickFlowRuntimeException;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.quickflow.listener.SingleFlowListener;
import cn.schoolwow.quickflow.listener.TryCatchFinallyHandler;
import cn.schoolwow.quickflow.util.QuickFlowConfigUtil;
import cn.schoolwow.quickflow.util.QuickFlowUtil;
import com.alibaba.fastjson.JSONArray;

public class QuickFlowExecutorInner {
    private FlowExecutorConfig flowExecutorConfig;

    private FlowExecutorRootConfig flowExecutorRootConfig;

    private FlowConfig flowConfig;

    public QuickFlowExecutorInner(FlowExecutorConfig flowExecutorConfig) {
        this.flowExecutorConfig = flowExecutorConfig;
        this.flowExecutorRootConfig = flowExecutorConfig.flowExecutorRootConfig;
        this.flowConfig = this.flowExecutorRootConfig.flowConfig;
    }

    /**
     * 执行业务逻辑
     */
    public FlowContext doExecute() {
        if(flowExecutorConfig.flowExecutorRootConfig.flowArray.isEmpty()){
            JSONArray flowArray = QuickFlowUtil.getFlowArray(flowExecutorConfig);
            flowExecutorConfig.flowExecutorRootConfig.flowArray.addAll(flowArray);
        }
        try {
            beforeExecuteBusiness();
            executeBusiness();
        } catch (Exception e) {
            handleBusinessException(e);
        } finally {
            handleBusinessFinally();
        }
        return flowExecutorConfig.flowContext;
    }

    /**执行流程列表之前*/
    private void beforeExecuteBusiness(){
        executeTryCatchFinallyHandler(true, flowExecutorConfig.tryCatchFinallyHandler, "tryStart", null);
        {
            boolean shouldExecuteGlobalTryCatchFinally = getGlobalHandlerShouldExecute("TryCatchFinally");
            flowExecutorConfig.recordContent((shouldExecuteGlobalTryCatchFinally?"执行":"不执行")+"全局tryCatchFinally处理器-tryStart");
            executeTryCatchFinallyHandler(shouldExecuteGlobalTryCatchFinally, flowConfig.flowConfigHandlerContext.tryCatchFinallyHandler, "tryStart", null);
        }
        {
            boolean shouldExecuteGlobalBeforeAfter = getGlobalHandlerShouldExecute("BeforeAfter");
            flowExecutorConfig.recordContent((shouldExecuteGlobalBeforeAfter?"执行":"不执行")+"全局beforeAfter处理器");
        }

        if(!flowExecutorConfig.compositeBusiness&&null==flowExecutorConfig.parentFlowExecutorConfig){
            flowExecutorConfig.recordContent("当前流程是主流程!流程id:"+flowExecutorRootConfig.id);
        }

        flowExecutorConfig.flowExecutorRootConfig.incrementFlowLevel();
        //子流程列表大于1或者只有一个流程但是该流程是复合流程，则打印当前流程名称
        if(flowExecutorConfig.flowList.size()>1||(flowExecutorConfig.flowList.size()==1&&flowExecutorConfig.flowList.get(0).name().startsWith("[复合流程]"))){
            flowExecutorConfig.printFlowTrace("["+flowExecutorConfig.name +"]");
        }
    }

    private void executeBusiness() throws Exception {
        for (BusinessFlow flow : flowExecutorConfig.flowList) {
            if(null==flow.name()){
                throw new IllegalArgumentException("流程名不能为空!涉及类:"+flow.getClass().getName());
            }
            flowExecutorConfig.currentFlowName = flow.name();
            flowExecutorConfig.getRemarkBuilder().setLength(0);
            flowExecutorConfig.currentFlow = flow;
            QuickFlowConfigUtil.handleHasFlowConfig(flow, flowExecutorConfig);
            QuickFlowConfigUtil.handleLoadFlowConfig(flow, flowExecutorConfig);

            long startTime = System.currentTimeMillis();
            try {
                executeSingleFlowHandler(true, flow, flowExecutorConfig.singleFlowListener, "before");
                {
                    boolean shouldExecuteGlobalSingleFlow = getGlobalHandlerShouldExecute("SingleFlow");
                    flowExecutorConfig.recordContent((shouldExecuteGlobalSingleFlow?"执行":"不执行")+"全局singleFlow-before处理器");
                    executeSingleFlowHandler(shouldExecuteGlobalSingleFlow, flow, flowConfig.flowConfigHandlerContext.singleFlowListener, "before");
                }
                startTime = System.currentTimeMillis();
                flow.executeBusinessFlow(flowExecutorConfig.flowContext);
                long endTime = System.currentTimeMillis();
                if(!flow.name().startsWith("[复合流程]")){
                    flowExecutorConfig.recordContent("当前流程不是复合流程");
                    flowExecutorConfig.printFlowTraceWithIndex("|" + (endTime - startTime) + "毫秒|" + flow.name() + flowExecutorConfig.getRemarkBuilder().toString());
                }else{
                    flowExecutorConfig.recordContent("当前流程是复合流程");
                }
            }catch (BrokenCurrentFlowException e){
                long endTime = System.currentTimeMillis();
                flowExecutorConfig.printFlowTraceWithIndex("|" + (endTime - startTime) + "毫秒|[x]|"+ flow.name() + "|当前流程中断|中断原因:" + e.getReason() + flowExecutorConfig.getRemarkBuilder().toString());
            }catch (BrokenCurrentCompositeBusinessException e){
                long endTime = System.currentTimeMillis();
                flowExecutorConfig.printFlowTraceWithIndex("|" + (endTime - startTime) + "毫秒|[x]|"+ flow.name() + "|当前复合流程中断|中断原因:" + e.getReason() + flowExecutorConfig.getRemarkBuilder().toString());
                flowExecutorConfig.flowExecutorRootConfig.decrementFlowLevel();
                break;
            }
            executeSingleFlowHandler(true, flow, flowExecutorConfig.singleFlowListener, "after");
            {
                boolean shouldExecuteGlobalSingleFlow = getGlobalHandlerShouldExecute("SingleFlow");
                flowExecutorConfig.recordContent((shouldExecuteGlobalSingleFlow?"执行":"不执行")+"全局singleFlow-after处理器");
                executeSingleFlowHandler(shouldExecuteGlobalSingleFlow, flow, flowConfig.flowConfigHandlerContext.singleFlowListener, "after");
            }
            flowExecutorConfig.currentFlowDataMap.clear();
        }
        executeTryCatchFinallyHandler(true, flowExecutorConfig.tryCatchFinallyHandler, "tryEnd", null);
        {
            boolean shouldExecuteGlobalTryCatchFinally = getGlobalHandlerShouldExecute("TryCatchFinally");
            flowExecutorConfig.recordContent((shouldExecuteGlobalTryCatchFinally?"执行":"不执行")+"全局tryCatchFinally处理器-tryEnd");
            executeTryCatchFinallyHandler(shouldExecuteGlobalTryCatchFinally, flowConfig.flowConfigHandlerContext.tryCatchFinallyHandler, "tryEnd", null);
        }
        flowExecutorConfig.currentCompositeFlowDataMap.clear();
    }

    private void handleBusinessException(Exception e){
        flowExecutorConfig.flowExecutorRootConfig.decrementFlowLevel();
        Exception targetException = e;
        QuickFlowRuntimeException quickFlowRuntimeException = null;
        if(e instanceof QuickFlowRuntimeException){
            targetException = ((QuickFlowRuntimeException)e).targetException;
            quickFlowRuntimeException = (QuickFlowRuntimeException) e;
        }else{
            quickFlowRuntimeException = new QuickFlowRuntimeException(e);
        }
        //判断异常类型
        if(targetException instanceof BrokenException){
            handleBrokenException((BrokenException) targetException);
        }else{
            handleException(e, quickFlowRuntimeException);
        }
    }

    private void handleBrokenException(BrokenException e){
        boolean shouldIgnoreBroken = getShouldIgnoreBroken();
        flowExecutorConfig.recordContent((shouldIgnoreBroken?"忽略":"不忽略")+"中断异常");
        if(null!=flowExecutorConfig.parentFlowExecutorConfig){
            flowExecutorConfig.printFlowTraceWithIndex("|[x]|"+(null!=flowExecutorConfig.currentFlow?flowExecutorConfig.currentFlow.name():"事件执行中断方法")+"|业务流程发生中断|原因:"+e.getReason()+(shouldIgnoreBroken?"|忽略该中断":"")+ flowExecutorConfig.getRemarkBuilder().toString());
        }else{
            //主流程
            flowExecutorConfig.flowExecutorRootConfig.brokenReason = e.getReason();
            flowExecutorConfig.printFlowTraceWithIndex("|[x]|"+(null!=flowExecutorConfig.currentFlow?flowExecutorConfig.currentFlow.name():"事件执行中断方法")+"|业务流程终止|原因:"+e.getReason()+flowExecutorConfig.getRemarkBuilder().toString());
        }
        //只要不是最外层流程，则需要抛出异常
        if(null!=flowExecutorConfig.parentFlowExecutorConfig){
            throw e;
        }
        if(!shouldIgnoreBroken){
            throw e;
        }
    }

    private void handleException(Exception targetException, QuickFlowRuntimeException quickFlowRuntimeException){
        boolean shouldIgnoreException = getShouldIgnoreException();
        flowExecutorConfig.recordContent((shouldIgnoreException?"忽略":"不忽略")+"抛出异常");
        String exceptionMessage = targetException.getClass().getName() + "-" + targetException.getMessage();
        if(null!=flowExecutorConfig.parentFlowExecutorConfig){
            //非主流程
            flowExecutorConfig.printFlowTraceWithIndex("|[x]|"+(null!=flowExecutorConfig.currentFlow?flowExecutorConfig.currentFlow.name():"事件抛出异常")+(shouldIgnoreException?"|忽略该异常":"")+"|异常信息:" + exceptionMessage);
            executeTryCatchFinallyHandler(true, flowExecutorConfig.tryCatchFinallyHandler, "catch", targetException);
        }else{
            flowExecutorConfig.printFlowTraceWithIndex("|[x]|"+(null!=flowExecutorConfig.currentFlow?flowExecutorConfig.currentFlow.name():"事件抛出异常")+(shouldIgnoreException?"|忽略该异常":"")+"|异常信息:" + exceptionMessage);
            executeTryCatchFinallyHandler(true, flowExecutorConfig.tryCatchFinallyHandler, "catch", targetException);
            //主流程
            flowExecutorConfig.flowExecutorRootConfig.exception = targetException;
            {
                boolean shouldExecuteGlobalTryCatchFinally = getGlobalHandlerShouldExecute("TryCatchFinally");
                flowExecutorConfig.recordContent((shouldExecuteGlobalTryCatchFinally?"执行":"不执行")+"全局tryCatchFinally处理器-catch");
                executeTryCatchFinallyHandler(shouldExecuteGlobalTryCatchFinally, flowConfig.flowConfigHandlerContext.tryCatchFinallyHandler, "catch", targetException);
            }
        }
        if(!shouldIgnoreException){
            if(targetException instanceof RuntimeException){
                RuntimeException runtimeException = (RuntimeException) targetException;
                throw runtimeException;
            }else{
                throw quickFlowRuntimeException;
            }
        }
    }

    private void handleBusinessFinally(){
        executeTryCatchFinallyHandler(true, flowExecutorConfig.tryCatchFinallyHandler, "finally", null);
        {
            boolean shouldExecuteGlobalTryCatchFinally = getGlobalHandlerShouldExecute("TryCatchFinally");
            flowExecutorConfig.recordContent((shouldExecuteGlobalTryCatchFinally?"执行":"不执行")+"全局tryCatchFinally处理器-finally");
            executeTryCatchFinallyHandler(shouldExecuteGlobalTryCatchFinally, flowConfig.flowConfigHandlerContext.tryCatchFinallyHandler, "finally", null);
        }
        //子流程列表大于1或者只有一个流程但是该流程是复合流程，则打印当前流程名称
        if(flowExecutorConfig.flowList.size()>1||(flowExecutorConfig.flowList.size()==1&&flowExecutorConfig.flowList.get(0).name().startsWith("[复合流程]"))){
            flowExecutorConfig.printFlowTrace("["+flowExecutorConfig.name +"]");
        }
        flowExecutorConfig.recordContent("================");
        if(null==flowExecutorConfig.flowExecutorRootConfig.exception&&null==flowExecutorConfig.flowExecutorRootConfig.brokenReason){
            flowExecutorConfig.flowExecutorRootConfig.decrementFlowLevel();
        }
    }

    private void executeTryCatchFinallyHandler(boolean shouldExecute, TryCatchFinallyHandler tryCatchFinallyHandler, String operation, Exception e) {
        if(null==tryCatchFinallyHandler||!shouldExecute){
            return;
        }
        long startTime = System.currentTimeMillis();
        try {
            switch (operation){
                case "tryStart":{tryCatchFinallyHandler.handleTryStart(flowExecutorConfig.flowContext);}break;
                case "tryEnd":{tryCatchFinallyHandler.handleTryEnd(flowExecutorConfig.flowContext);}break;
                case "catch":{tryCatchFinallyHandler.handleException(flowExecutorConfig.flowContext, e);}break;
                case "finally":{
                    if(flowExecutorConfig.flowExecutorRootConfig.flowConfig.flowConfigHandlerContext.tryCatchFinallyHandler==tryCatchFinallyHandler){
                        flowExecutorConfig.flowExecutorRootConfig.decrementFlowLevel();
                        flowExecutorConfig.printFlowTraceWithIndex(operation+":" + tryCatchFinallyHandler.name());
                    }
                    tryCatchFinallyHandler.handleFinally(flowExecutorConfig.flowContext);
                }break;
                default:{
                    throw new IllegalArgumentException("不支持调用该方法!方法名:"+operation);
                }
            }
            long endTime = System.currentTimeMillis();
            flowExecutorConfig.printFlowTraceWithIndex("|" + (endTime - startTime) + "毫秒|"+tryCatchFinallyHandler.name() + ":" + operation);
        }catch (Exception ex){
            if(ex instanceof QuickFlowRuntimeException){
                throw (QuickFlowRuntimeException)ex;
            }else{
                throw new QuickFlowRuntimeException(ex);
            }
        }
    }

    private void executeSingleFlowHandler(boolean shouldExecute, BusinessFlow flow, SingleFlowListener singleFlowListener, String operation) throws Exception {
        if(null==singleFlowListener||!shouldExecute){
            return;
        }
        switch (operation){
            case "before":{
                singleFlowListener.beforeExecuteFlow(flow, flowExecutorConfig.flowContext);
            };break;
            case "after":{
                singleFlowListener.afterExecuteFlow(flow, flowExecutorConfig.flowContext);
            };break;
            default:{
                throw new IllegalArgumentException("不支持调用该方法!方法名:"+operation);
            }
        }
    }

    private boolean getShouldIgnoreBroken(){
        FlowExecutorConfig currentFlowExecutorConfig = this.flowExecutorConfig;
        while(null!=currentFlowExecutorConfig){
            if(null!=currentFlowExecutorConfig.ignoreBroken){
                return currentFlowExecutorConfig.ignoreBroken;
            }
            currentFlowExecutorConfig = currentFlowExecutorConfig.parentFlowExecutorConfig;
        }
        return flowConfig.flowConfigSwitcherContext.ignoreBroken;
    }

    private boolean getShouldIgnoreException(){
        FlowExecutorConfig currentFlowExecutorConfig = this.flowExecutorConfig;
        while(null!=currentFlowExecutorConfig){
            if(null!=currentFlowExecutorConfig.ignoreException){
                return currentFlowExecutorConfig.ignoreException;
            }
            currentFlowExecutorConfig = currentFlowExecutorConfig.parentFlowExecutorConfig;
        }
        if(flowConfig.flowConfigSwitcherContext.ignoreException){
            return true;
        }
        return false;
    }

    private boolean getGlobalHandlerShouldExecute(String type){
        //最外层流程一定执行
        if(null==flowExecutorConfig.parentFlowExecutorConfig){
            return true;
        }
        //复合流程不执行
        if(flowExecutorConfig.compositeBusiness){
            return false;
        }
        //其他情况不执行
        return false;
    }

}
